﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;

using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using FluentAssertions;

namespace CodeStream.Testing.WebAutomation.UnitTests
{
    [TestClass]
    public class UITemplateSignatureTests
    {
        private static Assembly m_sampleAssembly;
        private static string m_sampleUIDefinitionCode;
            
        [ClassInitialize]
        public static void Initialize(TestContext testContext)
        {
            m_sampleUIDefinitionCode = UITemplateTestExtensions.GenerateDefinitionCode(
               Assembly.GetExecutingAssembly().GetManifestResourceStream("CodeStream.Testing.WebAutomation.UnitTests.UITemplateSignatureTests.xml"));
            m_sampleAssembly = UITemplateTestExtensions.CompileCode(m_sampleUIDefinitionCode,
                new string[]
                {
                    "System.dll",
                    "System.Core.dll",
                    new Uri(Assembly.GetAssembly(typeof(CodeStream.Testing.WebAutomation.UIDefinitionPage)).CodeBase).LocalPath,
                    new Uri(Assembly.GetAssembly(typeof(Microsoft.VisualStudio.TestTools.UITesting.BrowserWindow)).CodeBase).LocalPath,
                    new Uri(Assembly.GetAssembly(typeof(Microsoft.VisualStudio.TestTools.UITest.Extension.BrowserService)).CodeBase).LocalPath
                },
                Path.Combine(testContext.DeploymentDirectory, testContext.FullyQualifiedTestClassName + ".dll"));
        }

        [TestInitialize]
        public void LogCodeToDebug()
        {
            Debug.WriteLine(m_sampleUIDefinitionCode);
        }

        #region Code Signature Tests
        
        // verify page constructors and reset
        [TestMethod]
        public void UITemplateSignature_Verify_Page_Class()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UITestPage", typeof(BrowserWindow));

            // verify that the type has two constructors
            var constructors = pageType.GetConstructors();
            constructors.Should().HaveCount(3);

            // verify the default constructor
            var defaultConstructor = constructors.FirstOrDefault(constructor => constructor.GetParameters().Length == 0);
            defaultConstructor.Should().NotBeNull("Could not find constructor accepting {0} parameter(s) of type '{1}'", 1, typeof(Uri).FullName);

            // verify the signature of the uri constructor
            var uriConstructor = constructors.FirstOrDefault(constructor => constructor.GetParameters().Length == 1 && constructor.GetParameters()[0].ParameterType == typeof(Uri));
            uriConstructor.Should().NotBeNull("Could not find constructor accepting {0} parameter(s) of type '{1}'", 1, typeof(Uri).FullName);

            // verify the signature of the process constructor
            var processConstructor = constructors.FirstOrDefault(constructor => constructor.GetParameters().Length == 1 && constructor.GetParameters()[0].ParameterType == typeof(Process));
            processConstructor.Should().NotBeNull("Could not find constructor accepting {0} parameter(s) of type '{1}'", 1, typeof(Process).FullName);
        }

        // verify page single control
        [TestMethod]
        public void UITemplateSignature_Verify_Page_Single_Control_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UITestPage");

            var propertyInfo = pageType.ShouldHaveProperty("SingleControl");
            propertyInfo.PropertyType.Should().Be(typeof(HtmlDiv));
        }

        // verify page multiple control
        [TestMethod]
        public void UITemplateSignature_Verify_Page_Multiple_Control_Property()
        {            
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UITestPage");

            var propertyInfo = pageType.ShouldHaveProperty("MultipleControls");
            propertyInfo.PropertyType.Should().Be(typeof(HtmlDiv[]));
        }

        // verify page single container
        [TestMethod]
        public void UITemplateSignature_Verify_Page_Single_Container_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UITestPage");

            var propertyInfo = pageType.ShouldHaveProperty("SingleContainer");
            propertyInfo.PropertyType.FullName.Should().Be("TestNamespace.UISingleContainer");
        }

        // verify page multiple container
        [TestMethod]
        public void UITemplateSignature_Verify_Page_Multiple_Container_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UITestPage");

            var propertyInfo = pageType.ShouldHaveProperty("MultipleContainers");
            propertyInfo.PropertyType.FullName.Should().Be("TestNamespace.UIMultipleContainer[]");
        }

        // verify container constructors and reset
        [TestMethod]
        public void UITemplateSignature_Verify_Container_Class()
        {
            var containerType = m_sampleAssembly.ShouldHaveType("TestNamespace.UISingleContainer", typeof(HtmlDiv));

            // verify that the type has two constructors
            var constructors = containerType.GetConstructors();
            constructors.Should().HaveCount(1);

            // verify the signature of the constructor
            var uriConstructor = constructors.FirstOrDefault(constructor => constructor.GetParameters().Length == 1 && constructor.GetParameters()[0].ParameterType == typeof(UITestControl));
            uriConstructor.Should().NotBeNull("Could not find constructor accepting {0} parameter(s) of type '{1}'", 1, typeof(UITestControl).FullName);

            // verify the result method exists
            var resetMethod = containerType.ShouldHaveMethod("Reset");
            resetMethod.ReturnType.Should().Be(typeof(void), "when checking the return value of Reset()");
            resetMethod.GetParameters().Length.Should().Be(0);
        }

        // verify container single control
        [TestMethod]
        public void UITemplateSignature_Verify_Container_Single_Control_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UISingleContainer");

            var propertyInfo = pageType.ShouldHaveProperty("SingleControl");
            propertyInfo.PropertyType.Should().Be(typeof(HtmlDiv));
        }

        // verify container multiple control
        [TestMethod]
        public void UITemplateSignature_Verify_Container_Multiple_Control_Property()
        {            
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UISingleContainer");

            var propertyInfo = pageType.ShouldHaveProperty("MultipleControls");
            propertyInfo.PropertyType.Should().Be(typeof(HtmlDiv[]));
        }

        // verify container single container
        [TestMethod]
        public void UITemplateSignature_Verify_Container_Single_Container_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UISingleContainer");

            var propertyInfo = pageType.ShouldHaveProperty("SingleContainer");
            propertyInfo.PropertyType.FullName.Should().Be("TestNamespace.UISingleContainer_SingleContainer");
        }

        // verify container multiple container
        [TestMethod]
        public void UITemplateSignature_Verify_Container_Multiple_Container_Property()
        {
            var pageType = m_sampleAssembly.ShouldHaveType("TestNamespace.UISingleContainer");

            var propertyInfo = pageType.ShouldHaveProperty("MultipleContainers");
            propertyInfo.PropertyType.FullName.Should().Be("TestNamespace.UISingleContainer_MultipleContainer[]");
        }

        #endregion



   
    }
}
